//
// Created by jsz on 2021/6/10.
//

#define WORK_DIR        "protocol"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "protocol.h"

#define MAX_LINE_LEN  256


void print_frame(const char *desc, char *frame, int frame_len)
{
    int i;

    printf("==========\n%s\n", desc);
    for (i=0; i<frame_len; i++) {
        printf("0x%02hhx ", frame[i]);
        if ((i % 8) == 7) putchar('\n');
    }
    printf("\n===============\n\n");
}

/*
 * 解析报文行
 * @param in: 输入行
 * @param len: 输入行长度，不含结尾\r\n等
 * @param frame: 解析后存放到这里
 * @param frame_len: 帧字节数
 */
int parse_frame(char *in, int len, char *frame, int *frame_len)
{
    long byte;
    int count;
    char *p = NULL, *q = NULL, *start = NULL;

    count = 0;
    // p指向当前位置，q指向下一个位置
    for (p=in; p<in+len && (q = strchr(p, ' ')); p=q) {
        *q++ = '\0';
        // 过滤' '
        while (*q == ' ') q++;

        // 按16进制，取值
        byte = strtol(p, NULL, 16);
        frame[count++] = (char)byte;
    }

    // 处理最后一个' '之后的内容
    if (*p != '\0') {
        byte = strtol(p, NULL, 16);
        frame[count++] = (char)byte;
    }
    *frame_len = count;
    return 1;
}

/*
 * 从报文文件解析出各个完整帧
 * @p_frame_pair: 被动帧对
 * @num_p_pair: 对数
 * @a_frame_pair: 主动帧对
 * @num_a_pair: 对数
 */
int default_parse_protocol(FILE *fp, frame_pair_t *p_frame_pair, int *num_p_pair, frame_pair_t *a_frame_pair, int *num_a_pair)
{
    int read_len, len;
    int num_p = 0, num_a = 0;
    int req_correct = 0, resp_correct = 0;
    int in_active = 0;
    char req[MAX_FRAME_LEN], resp[MAX_FRAME_LEN];
    char *p, line[MAX_LINE_LEN] = {0};

    while (fgets(line, MAX_LINE_LEN, fp)) {
        /*
         * // 被动接收
         * >[接收帧]
         * <[发送帧]
         *
         * =====
         * // 主动发送
         * <[发送帧]
         * >[接收帧]
         *
         */
        len = strlen(line);
        for (p=&line[len-1]; p!=line; p--) {
            if (*p != '\r' && *p != '\n')
                break;
            *p = '\0';
        }
        printf("read (%s)\n", line);
        if (strlen(line) == 0) continue;
        if (!memcmp(line, "=====", 5)) {
            in_active = 1;
        }
        if (line[0] == '>') {
            if (!in_active) {
                if (parse_frame(&line[1], strlen(line)-1, p_frame_pair[num_p].req, &p_frame_pair[num_p].req_len)) {
                    req_correct = 1;
                }
            }
            else {
                if (resp_correct && parse_frame(&line[1], strlen(line)-1, a_frame_pair[num_a].resp, &a_frame_pair[num_a].resp_len)) {
                    num_a++;
                    resp_correct = 0;
                }
            }
        }
        else if (line[0] == '<') {
            if (!in_active) {
                if (req_correct && parse_frame(&line[1], strlen(line)-1, p_frame_pair[num_p].resp, &p_frame_pair[num_p].resp_len)) {
                    num_p++;
                    req_correct = 0;
                }
            }
            else {
                if (parse_frame(&line[1], strlen(line)-1, a_frame_pair[num_a].req, &a_frame_pair[num_a].req_len)) {
                    resp_correct = 1;
                }
            }
        }
    }
    printf("read pasitive %d pair\n", num_p);
    printf("read active %d pair\n", num_a);
    *num_p_pair = num_p;
    *num_a_pair = num_a;

    return 1;
}

static int frame_compare(void *a, int a_size, void *b, int b_size)
{
    if (a_size != b_size)
        return 0;
    return !memcmp(a, b, a_size);
}

// 从请求获得对应响应
int protocol_get_resp(void *req, int req_size, void *resp, int max_resp_size, void *priv_data)
{
    int i;
    protocol_resolver_t *resolver = (protocol_resolver_t *)priv_data;

    for (i=0; i<resolver->total_p_pair; i++) {
        if (frame_compare(req, req_size, resolver->p_frame_pair[i].req, resolver->p_frame_pair[i].req_len)) {
            memcpy(resp, resolver->p_frame_pair[i].resp, MAX_FRAME_LEN);
            return resolver->p_frame_pair[i].resp_len;
        }
    }
    return 0;
}

// 查询下一主动发的请求
int protocol_get_next_req(void *req, int max_output_size, void *priv_data)
{
    int idx, req_len;
    protocol_resolver_t *resolver = (protocol_resolver_t *)priv_data;

    idx = resolver->next_req_idx;
    memcpy(req, resolver->a_frame_pair[idx].req, MAX_FRAME_LEN);
    req_len = resolver->a_frame_pair[idx].req_len;
    print_frame("send frame", req, req_len);

    return req_len;
}

// 检查收到的应答是否正确
int protocol_is_valid_resp(void *resp, int resp_size, void *priv_data)
{
    int result, curr_idx;
    protocol_resolver_t *resolver = (protocol_resolver_t *)priv_data;

    curr_idx = resolver->next_req_idx;
    print_frame("expect frame", resolver->a_frame_pair[curr_idx].resp, resolver->a_frame_pair[curr_idx].resp_len);
    if (frame_compare(resp, resp_size, resolver->a_frame_pair[curr_idx].resp, resolver->a_frame_pair[curr_idx].resp_len))
        result = 1;
    else
        result = 0;
    resolver->next_req_idx = (resolver->next_req_idx + 1) % resolver->total_a_pair;
    return result;
}

protocol_resolver_t *protocol_init(const char *protocol_name)
{
    FILE *frame_fp;
    char proto_path[128];
    protocol_resolver_t *resolver = NULL;

    // 判断协议报文文件是否存在
    snprintf(proto_path, 128, "%s/%s", WORK_DIR, protocol_name);
    if (access(proto_path, F_OK) != 0) {
        printf("file: %s no exist\n", proto_path);
        return NULL;
    }

    frame_fp = fopen(proto_path, "rb");
    if (frame_fp < 0) return NULL;

    // 为resolver分配空间
    resolver = calloc(1, sizeof(protocol_resolver_t));
    if (resolver == NULL) {
        printf("calloc failed\n");
        return NULL;
    }

    // 解析报文文件
    if (!default_parse_protocol(frame_fp, resolver->p_frame_pair, &resolver->total_p_pair, resolver->a_frame_pair, &resolver->total_a_pair)) {
        printf("parser %s failed\n", proto_path);
        goto err_return;
    }
    fclose(frame_fp);

    // 初始化resolver
    resolver->name = protocol_name;
    resolver->next_req_idx = 0;
    resolver->get_next_req = protocol_get_next_req;
    resolver->get_resp = protocol_get_resp;
    resolver->is_valid_resp = protocol_is_valid_resp;

    return resolver;

err_return:
    if (resolver)
        free(resolver);
    if (frame_fp)
        fclose(frame_fp);
    return NULL;
}


void protocol_destroy(protocol_resolver_t *resolver)
{
    if (resolver) {
        free(resolver);
    }
}
